/***********************************************
* Filename:  		DXScreenRender.cpp
* Date:      		01/12/2014
* Mod. Date: 		01/12/2014
* Author:    		Night
* Purpose:   		Creates a quad which will uniformly
					fit the screen and render our "texture"
************************************************/

#include "DXScreenRender.h"

#if _DEBUG
#include <cassert>
#endif

struct VERTEX_POS_UV
{
	D3DXVECTOR3 Position;
	D3DXVECTOR2 UV;
};

CDXScreenRender::CDXScreenRender( void )
{
	m_ppDevice = nullptr;
	m_pEffect = nullptr;
	m_pTexture = nullptr;
	m_pVertexBuffer = nullptr;
	m_pVertexDecl = nullptr;
	m_pIndexBuffer = nullptr;
};

CDXScreenRender::~CDXScreenRender( void )
{
};

void CDXScreenRender::Init(  IDirect3DDevice9 **_ppDevice, const unsigned int _unWidth, const unsigned int _unHeight )
{
	if( _ppDevice == nullptr || (*_ppDevice) == nullptr )
		return;

	m_ppDevice = _ppDevice;

	IDirect3DDevice9 *pDevice = (*m_ppDevice);
	if( m_pEffect == nullptr )
	{
#if _DEBUG
		D3DXCreateEffectFromFileA( pDevice, "src/render/DirectX/BaseShader.fx", 0, 0, 
			D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
			0, &m_pEffect, 0 );
#else
		D3DXCreateEffectFromFileA( pDevice, "src/render/DirectX/BaseShader.fx", 0, 0, 
			0, 0, &m_pEffect, 0 );
#endif
	}

	if( m_pTexture == nullptr )
	{
		pDevice->CreateTexture( _unWidth, _unHeight, 1, 0, D3DFMT_X1R5G5B5, D3DPOOL_DEFAULT, &m_pTexture, 0 );
	}

	if( m_pVertexBuffer == nullptr )
	{
		pDevice->CreateVertexBuffer( 4 * sizeof( VERTEX_POS_UV ), D3DUSAGE_WRITEONLY, 0,
			D3DPOOL_DEFAULT, &this->m_pVertexBuffer, 0 );
	}

	if( m_pVertexDecl == nullptr )
	{
		D3DVERTEXELEMENT9 decl[] =
		{
		    {0,0,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION,0},
		    {0,12,D3DDECLTYPE_FLOAT2,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_TEXCOORD,0},
		    D3DDECL_END()
		};

		pDevice->CreateVertexDeclaration( decl, &this->m_pVertexDecl );
	}

	if( m_pIndexBuffer == nullptr )
	{
		unsigned int quadindicies[] = 
		{
			0,1,3,
			3,1,2
		};

		pDevice->CreateIndexBuffer( (6 * sizeof(unsigned int) ), 
			D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &m_pIndexBuffer, 0);

		void *pBuffer = nullptr;
		m_pIndexBuffer->Lock( 0, 6 * sizeof( unsigned int ), &pBuffer, 0 );
		memcpy( pBuffer, quadindicies, 6 * sizeof( unsigned ) );
		m_pIndexBuffer->Unlock();
	}

	m_pEffect->SetTexture( "diffuseMap", m_pTexture );

	UpdateQuad( _unWidth, _unHeight );
};

void CDXScreenRender::Release( void )
{
	m_ppDevice = nullptr;

	if( m_pEffect != nullptr )
	{
		m_pEffect->Release();
		m_pEffect = nullptr;
	}

	if( m_pTexture != nullptr )
	{
		m_pTexture->Release();
		m_pTexture = nullptr;
	}

	if( m_pVertexBuffer != nullptr )
	{
		m_pVertexBuffer->Release();
		m_pVertexBuffer = nullptr;
	}

	if( m_pVertexDecl != nullptr )
	{
		m_pVertexDecl->Release();
		m_pVertexDecl = nullptr;
	}

	if( m_pIndexBuffer != nullptr )
	{
		m_pIndexBuffer->Release();
		m_pIndexBuffer = nullptr;
	}
};

void CDXScreenRender::UpdateQuad( const unsigned int _unWidth, const unsigned int _unHeight )
{
	if( m_ppDevice == nullptr || (*m_ppDevice) == nullptr )
		return;

	D3DSURFACE_DESC backbuffer;
	IDirect3DSurface9 *bBuffer = 0; 
	(*m_ppDevice)->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer);
	bBuffer->GetDesc( &backbuffer );
	bBuffer->Release();

	VERTEX_POS_UV quad[] =
	{
		{ D3DXVECTOR3( -1, 1, 0.0f), D3DXVECTOR2((1.0f/backbuffer.Width)*0.5f,(1.0f/backbuffer.Height)*0.5f)},		// topleft
		{ D3DXVECTOR3( 1, 1, 0.0f), D3DXVECTOR2(1+(1.0f/backbuffer.Width)*0.5f,(1.0f/backbuffer.Height)*0.5f)},		// topright
		{ D3DXVECTOR3( 1, -1, 0.0f), D3DXVECTOR2(1+(1.0f/backbuffer.Width)*0.5f,1+(1.0f/backbuffer.Height)*0.5f)},	// btmright
		{ D3DXVECTOR3( -1, -1, 0.0f), D3DXVECTOR2((1.0f/backbuffer.Width)*0.5f,1+(1.0f/backbuffer.Height)*0.5f)}	// btmleft
	};

	// Load the vertex data
	void *pBuffer = nullptr;
	m_pVertexBuffer->Lock( 0, 4 * sizeof( VERTEX_POS_UV ), &pBuffer, 0 );
	memcpy( pBuffer, quad, 4 * sizeof( VERTEX_POS_UV ) );
	m_pVertexBuffer->Unlock();
};

void CDXScreenRender::UpdateTexture( const char *_szFilePathToTexture )
{
	if( m_pTexture != nullptr )
	{
		m_pTexture->Release();
		m_pTexture = nullptr;
	}

	HRESULT hr = D3DXCreateTextureFromFileA( (*m_ppDevice), _szFilePathToTexture, &m_pTexture );
	m_pEffect->SetTexture( "diffuseMap", m_pTexture );
};
	
void CDXScreenRender::UpdateTexture( void )
{

};

void CDXScreenRender::Render( void )
{
#if _DEBUG
	if( m_ppDevice == nullptr || (*m_ppDevice) == nullptr || m_pEffect == nullptr ||
		m_pTexture == nullptr || m_pVertexBuffer == nullptr || m_pVertexDecl == nullptr || m_pIndexBuffer == nullptr )
	{
		assert( !"Broken Screen Render Things..." );
		return;
	}
#endif

	IDirect3DDevice9 *pDevice = (*m_ppDevice);
	pDevice->SetVertexDeclaration( m_pVertexDecl );
	pDevice->SetStreamSource( 0, m_pVertexBuffer,
		0, sizeof( VERTEX_POS_UV ) );
	pDevice->SetIndices( m_pIndexBuffer );

	unsigned int passes = 0;
	this->m_pEffect->Begin( &passes, 0 );
	for( unsigned int i = 0; i < passes; i++ )
	{
		m_pEffect->BeginPass( i );

		m_pEffect->CommitChanges();
		pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);

		m_pEffect->EndPass();
	}
};
